/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2006 - 2013 ScriptDev2 <http://www.scriptdev2.com/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

/* ScriptData
 SDName: Guards
 SD%Complete: 100
 SDComment:
 SDCategory: Guards
 EndScriptData */

/* ContentData
 guard_generic
 guard_shattrath_aldor
 guard_shattrath_scryer
 EndContentData */

#include "ScriptPCH.h"
#include "GuardAI.h"

enum GuardGeneric
{
    GENERIC_CREATURE_COOLDOWN = 5000,

    SAY_GUARD_SIL_AGGRO1 = -1070001, SAY_GUARD_SIL_AGGRO2 = -1070002, SAY_GUARD_SIL_AGGRO3 = -1070003,

    NPC_CENARION_HOLD_INFANTRY = 15184, NPC_STORMWIND_CITY_GUARD = 68, NPC_STORMWIND_CITY_PATROLLER = 1976, NPC_ORGRIMMAR_GRUNT = 3296
};

class guard_generic: public CreatureScript
{
public:
    guard_generic () :
            CreatureScript("guard_generic")
    {
    }

    struct guard_genericAI: public GuardAI
    {
        guard_genericAI (Creature* creature) :
                GuardAI(creature)
        {
        }

        void Reset ()
        {
            globalCooldown = 0;
            buffTimer = 0;
        }

        void EnterCombat (Unit* who)
        {
            if (me->GetEntry() == NPC_CENARION_HOLD_INFANTRY)
                DoScriptText(RAND(SAY_GUARD_SIL_AGGRO1, SAY_GUARD_SIL_AGGRO2, SAY_GUARD_SIL_AGGRO3), me, who);
            if (SpellEntry const* spell = me->reachWithSpellAttack(who))
                DoCast(who, spell->Id);
        }

        void UpdateAI (const uint32 diff)
        {
            //Always decrease our global cooldown first
            if (globalCooldown > diff)
                globalCooldown -= diff;
            else
                globalCooldown = 0;

            //Buff timer (only buff when we are alive and not in combat
            if (me->isAlive() && !me->isInCombat())
            {
                if (buffTimer <= diff)
                {
                    //Find a spell that targets friendly and applies an aura (these are generally buffs)
                    SpellEntry const *info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_AURA);

                    if (info && !globalCooldown)
                    {
                        //Cast the buff spell
                        DoCast(me, info->Id);

                        //Set our global cooldown
                        globalCooldown = GENERIC_CREATURE_COOLDOWN;

                        //Set our timer to 10 minutes before rebuff
                        buffTimer = 600000;
                    }          //Try again in 30 seconds
                    else
                        buffTimer = 30000;
                }
                else
                    buffTimer -= diff;
            }

            //Return since we have no target
            if (!UpdateVictim())
                return;

            // Make sure our attack is ready and we arn't currently casting
            if (me->isAttackReady() && !me->IsNonMeleeSpellCasted(false))
            {
                //If we are within range melee the target
                if (me->IsWithinMeleeRange(me->getVictim()))
                {
                    bool healing = false;
                    SpellEntry const *info = NULL;

                    //Select a healing spell if less than 30% hp
                    if (me->HealthBelowPct(30))
                        info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);

                    //No healing spell available, select a hostile spell
                    if (info)
                        healing = true;
                    else
                        info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, 0, 0, SELECT_EFFECT_DONTCARE);

                    //20% chance to replace our white hit with a spell
                    if (info && urand(0, 99) < 20 && !globalCooldown)
                    {
                        //Cast the spell
                        if (healing)
                            DoCast(me, info->Id);
                        else
                            DoCast(me->getVictim(), info->Id);

                        //Set our global cooldown
                        globalCooldown = GENERIC_CREATURE_COOLDOWN;
                    }
                    else
                        me->AttackerStateUpdate(me->getVictim());

                    me->resetAttackTimer();
                }
            }
            else
            {
                //Only run this code if we arn't already casting
                if (!me->IsNonMeleeSpellCasted(false))
                {
                    bool healing = false;
                    SpellEntry const *info = NULL;

                    //Select a healing spell if less than 30% hp ONLY 33% of the time
                    if (me->HealthBelowPct(30) && 33 > urand(0, 99))
                        info = SelectSpell(me, 0, 0, SELECT_TARGET_ANY_FRIEND, 0, 0, 0, 0, SELECT_EFFECT_HEALING);

                    //No healing spell available, See if we can cast a ranged spell (Range must be greater than ATTACK_DISTANCE)
                    if (info)
                        healing = true;
                    else
                        info = SelectSpell(me->getVictim(), 0, 0, SELECT_TARGET_ANY_ENEMY, 0, 0, NOMINAL_MELEE_RANGE, 0, SELECT_EFFECT_DONTCARE);

                    //Found a spell, check if we arn't on cooldown
                    if (info && !globalCooldown)
                    {
                        //If we are currently moving stop us and set the movement generator
                        if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE)
                        {
                            me->GetMotionMaster()->Clear(false);
                            me->GetMotionMaster()->MoveIdle();
                        }

                        //Cast spell
                        if (healing)
                            DoCast(me, info->Id);
                        else
                            DoCast(me->getVictim(), info->Id);

                        //Set our global cooldown
                        globalCooldown = GENERIC_CREATURE_COOLDOWN;
                    }          //If no spells available and we arn't moving run to target
                    else if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
                    {
                        //Cancel our current spell and then mutate new movement generator
                        me->InterruptNonMeleeSpells(false);
                        me->GetMotionMaster()->Clear(false);
                        me->GetMotionMaster()->MoveChase(me->getVictim());
                    }
                }
            }

            DoMeleeAttackIfReady();
        }

        void DoReplyToTextEmote (uint32 emote)
        {
            switch (emote)
            {
            case TEXTEMOTE_KISS:
                me->HandleEmoteCommand(EMOTE_ONESHOT_BOW);
                break;
            case TEXTEMOTE_WAVE:
                me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE);
                break;
            case TEXTEMOTE_SALUTE:
                me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
                break;
            case TEXTEMOTE_SHY:
                me->HandleEmoteCommand(EMOTE_ONESHOT_FLEX);
                break;
            case TEXTEMOTE_RUDE:
            case TEXTEMOTE_CHICKEN:
                me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
                break;
            }
        }

        void ReceiveEmote (Player* player, uint32 textEmote)
        {
            switch (me->GetEntry())
            {
            case NPC_STORMWIND_CITY_GUARD:
            case NPC_STORMWIND_CITY_PATROLLER:
            case NPC_ORGRIMMAR_GRUNT:
                break;
            default:
                return;
            }

            if (!me->IsFriendlyTo(player))
                return;

            DoReplyToTextEmote(textEmote);
        }

    private:
        uint32 globalCooldown;
        uint32 buffTimer;
    };

    CreatureAI *GetAI (Creature* creature) const
    {
        return new guard_genericAI(creature);
    }
};

enum GuardShattrath
{
    SPELL_BANISHED_SHATTRATH_A = 36642, SPELL_BANISHED_SHATTRATH_S = 36671, SPELL_BANISH_TELEPORT = 36643, SPELL_EXILE = 39533
};

class guard_shattrath_scryer: public CreatureScript
{
public:
    guard_shattrath_scryer () :
            CreatureScript("guard_shattrath_scryer")
    {
    }

    struct guard_shattrath_scryerAI: public GuardAI
    {
        guard_shattrath_scryerAI (Creature* creature) :
                GuardAI(creature)
        {
        }

        void Reset ()
        {
            banishTimer = 5000;
            exileTimer = 8500;
            playerGUID = 0;
            canTeleport = false;
        }

        void UpdateAI (const uint32 diff)
        {
            if (!UpdateVictim())
                return;

            if (canTeleport)
            {
                if (exileTimer <= diff)
                {
                    if (Unit* temp = Unit::GetUnit(*me, playerGUID))
                    {
                        temp->CastSpell(temp, SPELL_EXILE, true);
                        temp->CastSpell(temp, SPELL_BANISH_TELEPORT, true);
                    }
                    playerGUID = 0;
                    exileTimer = 8500;
                    canTeleport = false;
                }
                else
                    exileTimer -= diff;
            }
            else if (banishTimer <= diff)
            {
                Unit* temp = me->getVictim();
                if (temp && temp->GetTypeId() == TYPEID_PLAYER)
                {
                    DoCast(temp, SPELL_BANISHED_SHATTRATH_A);
                    banishTimer = 9000;
                    playerGUID = temp->GetGUID();
                    if (playerGUID)
                        canTeleport = true;
                }
            }
            else
                banishTimer -= diff;

            DoMeleeAttackIfReady();
        }

    private:
        uint32 exileTimer;
        uint32 banishTimer;
        uint64 playerGUID;
        bool canTeleport;
    };

    CreatureAI *GetAI (Creature *creature) const
    {
        return new guard_shattrath_scryerAI(creature);
    }
};

class guard_shattrath_aldor: public CreatureScript
{
public:
    guard_shattrath_aldor () :
            CreatureScript("guard_shattrath_aldor")
    {
    }

    struct guard_shattrath_aldorAI: public GuardAI
    {
        guard_shattrath_aldorAI (Creature* creature) :
                GuardAI(creature)
        {
        }

        void Reset ()
        {
            banishTimer = 5000;
            exileTimer = 8500;
            playerGUID = 0;
            canTeleport = false;
        }

        void UpdateAI (const uint32 diff)
        {
            if (!UpdateVictim())
                return;

            if (canTeleport)
            {
                if (exileTimer <= diff)
                {
                    if (Unit* temp = Unit::GetUnit(*me, playerGUID))
                    {
                        temp->CastSpell(temp, SPELL_EXILE, true);
                        temp->CastSpell(temp, SPELL_BANISH_TELEPORT, true);
                    }
                    playerGUID = 0;
                    exileTimer = 8500;
                    canTeleport = false;
                }
                else
                    exileTimer -= diff;
            }
            else if (banishTimer <= diff)
            {
                Unit* temp = me->getVictim();
                if (temp && temp->GetTypeId() == TYPEID_PLAYER)
                {
                    DoCast(temp, SPELL_BANISHED_SHATTRATH_S);
                    banishTimer = 9000;
                    playerGUID = temp->GetGUID();
                    if (playerGUID)
                        canTeleport = true;
                }
            }
            else
                banishTimer -= diff;

            DoMeleeAttackIfReady();
        }
    private:
        uint32 exileTimer;
        uint32 banishTimer;
        uint64 playerGUID;
        bool canTeleport;
    };

    CreatureAI *GetAI (Creature *creature) const
    {
        return new guard_shattrath_aldorAI(creature);
    }
};

void AddSC_guards ()
{
    new guard_generic;
    new guard_shattrath_aldor;
    new guard_shattrath_scryer;
}
